/*
 * @Author: zi.yang
 * @Date: 2021-04-16 11:44:26
 * @LastEditors: zi.yang
 * @LastEditTime: 2021-10-04 20:09:05
 * @Description: axios 请求封装
 * @FilePath: \ziYangPM\src\Utils\request.js
 */
import axios from 'axios'
import router from '../router'
import refreshToken from './refreshToken'
import PmMessage from '@/components/PmPopup/PmMessage'
import MessageInterceptor from './messageInterceptor'

// 创建axios实例
const service = axios.create({
  validateStatus (status) {
    // 设置默认的合法的状态,不在范围内则不抛出异常
    return status >= 200 && status < 1080
  },
  // axios中请求配置有baseURL选项，表示请求URL公共部分
  baseURL: process.env.VUE_APP_BASE_API,
  // 超时
  timeout: 10000,
  // 请求头
  headers: {
    'Content-Type': 'application/json;charset=utf-8'
  }
})

// 请求重试次数
service.defaults.retry = 3
// 请求重试时间间隔
service.defaults.retryDelay = 1000
// 是否重试
service.defaults.shouldRetry = true

const message = new PmMessage()
const msgInter = new MessageInterceptor()

// 是否正在刷新的标记
let isRefreshing = false
const requests = []
// 响应拦截器
service.interceptors.response.use(
  // 服务器响应请求
  response => {
    // 状态码
    const { status } = response

    // 没有状态码直接 return
    const hasStatus = status === '' || status === undefined || status === null
    if (hasStatus) return Promise.reject(response)

    // 状态码检查
    if (status === 200) { // 检查是响应状态是否是 200
      return Promise.resolve(response)
    } else if (status === 401) { // 401: 未登录
      router.replace({ path: '/auth/sign-in1' })
    } else if (status === 403) { // 403 token过期
      if (!isRefreshing) {
        isRefreshing = true
        return refreshToken(requests)
          .then(() => service(response.config))
          .finally(() => { isRefreshing = false })
      } else {
        // 返回未执行 resolve 的 Promise
        return new Promise(resolve => {
          // 用函数形式将 resolve 存入，等待刷新后再执行
          requests.push(() => {
            resolve(service(response.config))
          })
        })
      }
    } else if (status === 404) { // 404请求不存在
      message.error('网络请求不存在', 3)
    }
    // 响应状态不是 200 则作为错误处理
    return Promise.reject(response)
  },
  // 服务器状态码不是200的情况
  error => {
    // 异常信息
    const errMsg = error.message
    // 收集消息
    let msg = ''
    // 判断消息所属错误
    if (errMsg === 'Network Error') {
      // 网络链接异常
      msg = '后端接口连接异常'
    } else if (errMsg.includes('timeout')) {
      // 请求超时
      msg = '系统接口请求超时'
    } else if (errMsg.includes('Request failed with status code')) {
      // 系统接口请求失败
      msg = `系统接口 ${error.response.status} ${error.response.statusText} 异常`
    } else {
      // 其他未知错误
      msg = '未知错误，请联系管理员'
    }
    if (!msgInter.checkQueue(msg)) {
      msgInter.enqueue(msg)
      // 提示错误消息
      message.error(msg, 3, () => msgInter.dequeue(msg))
    }

    return Promise.reject(error)
  }
)

const httpRequest = {
  /**
   * json, 请求 JSON 文件
   * @param {String} url [请求的 json 文件名称]
   */
  json (url) {
    return new Promise((resolve, reject) => {
      service
        .get(`${url}.json`)
        .then(res => {
          resolve(res.data)
        })
        .catch(err => {
          reject(err)
        })
    })
  },
  /**
   * get方法，对应get请求
   * @param {String} url [请求的url地址]
   * @param {Object} params [请求时携带的参数]
   * @param {Object} header [自定义请求头]
   */
  get (url, params, headers = {}) {
    return new Promise((resolve, reject) => {
      service
        .get(url, { params, headers })
        .then(res => {
          if (res.data.code === 200) {
            return resolve(res.data)
          }
          reject(res.data)
        })
        .catch(err => {
          if (err.data) {
            return reject(err.data)
          }
        })
    })
  },
  /**
   * post方法，对应post请求
   * @param {String} url [请求的url地址]
   * @param {Object} data [请求时携带的数据]
   * @param {Object} header [自定义请求头]
   */
  post (url, data, headers = {}) {
    return new Promise((resolve, reject) => {
      service
        .post(url, data, { headers })
        .then(res => {
          if (res.data.code === 200) {
            return resolve(res.data)
          }
          reject(res.data)
        })
        .catch(err => {
          if (err.data) {
            return reject(err.data)
          }
        })
    })
  },
  /**
   * put方法，对应put请求,用于更新数据.
   * @param {String} url [请求的url地址]
   * @param {Object} data [请求时携带的数据]
   * @param {Object} header [自定义请求头]
   */
  put (url, data, headers = {}) {
    return new Promise((resolve, reject) => {
      service
        .put(url, data, { headers })
        .then(res => {
          if (res.data.code === 200) {
            return resolve(res.data)
          }
          reject(res.data)
        })
        .catch(err => {
          if (err.data) {
            return reject(err.data)
          }
        })
    })
  },
  /**
   * delete方法，对应delete请求,用于删除数据.
   * @param {String} url [请求的url地址]
   * @param {Object} data [请求时携带的数据]
   * @param {Object} header [自定义请求头]
   */
  delete (url, params, headers = {}) {
    return new Promise((resolve, reject) => {
      service
        .delete(url, { params, headers })
        .then(res => {
          if (res.data.code === 200) {
            return resolve(res.data)
          }
          reject(res.data)
        })
        .catch(err => {
          if (err.data) {
            return reject(err.data)
          }
        })
    })
  },
  /**
   * upload方法,用于上传文件.
   * @param {String} url [请求的url地址]
   * @param {Object} data [请求时携带的参数]
   * @param {Function} onUploadProgress [上传文件的进度]
   */
  upload (url, data, onUploadProgress = () => {}) {
    return new Promise((resolve, reject) => {
      service
        .post({
          url,
          data,
          headers: { 'Content-Type': 'multipart/form-data' },
          onUploadProgress,
          timeout: 0
        })
        .then(res => {
          resolve(res.data)
        })
        .catch(err => {
          if (err.data) {
            return reject(err.data)
          }
        })
    })
  },
  /**
   * download方法,用于下载.
   * @param {String} url [请求的url地址]
   * @param {Object} data [请求时携带的参数]
   * @param {Function} onDownloadProgress [下载文件的进度]
   */
  download (url, data, onDownloadProgress = () => {}) {
    return new Promise((resolve, reject) => {
      service
        .post({
          url,
          data,
          responseType: 'blob',
          onDownloadProgress,
          timeout: 0
        })
        .then(res => {
          resolve(res.data)
        })
        .catch(err => {
          if (err.data) {
            return reject(err.data)
          }
        })
    })
  },
  /**
   * imgStream 方法,用于请求图片流.
   * @param {String} url [请求的url地址]
   * @param {Object} params [请求时携带的参数]
   */
  imgStream (url, params) {
    return new Promise((resolve, reject) => {
      service
        .get(url, {
          params,
          responseType: 'blob'
        })
        .then(res => {
          resolve(res.data)
        })
        .catch(err => {
          if (err.data) {
            return reject(err.data)
          }
        })
    })
  }
}

export default httpRequest
